/*
    BibleNotebook - A bible reader software
    Copyright (C) 2014  Williams Fernando Lopez

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
 */

package com.simplebible.bible;

import wl.util.Utils;
import java.awt.Color;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import com.simplebible.util.VirtualFolder;
import com.simplebible.bible.objects.Abreviation;
import com.simplebible.bible.objects.Bible;
import com.simplebible.bible.objects.Book;
import com.simplebible.bible.objects.BookLazy;
import com.simplebible.bible.objects.BookMark;
import com.simplebible.bible.objects.BookMarkGroup;
import com.simplebible.bible.objects.Chapter;
import com.simplebible.bible.objects.ChapterLazy;
import com.simplebible.bible.objects.Note;
import com.simplebible.objects.Preferences;
import com.simplebible.bible.objects.Referencia;
import com.simplebible.bible.objects.Title;
import com.simplebible.bible.objects.Verse;

/**
 *
 * @author Williams Lopez
 */
public class BibleReader {

    private static String separatorTopic     = "{st}";
    private static String separatorLine      = "{sl}";
    private static String separatorColumn    = "{sc}";
    private static String startReference     = "{+";
    private static String endReference       = "+}";
    private static String separatorReference = "{sr}";

    private static String separatorNote     = "{nt}";

    private static String rexSeparatorTopic     = "\\{st\\}";
    private static String rexSeparatorLine      = "\\{sl\\}";
    private static String rexSeparatorColumn    = "\\{sc\\}";
    private static String rexStartReference     = "\\{\\+";
    private static String rexSndReference       = "\\+\\}";
    private static String rexSeparatorReference = "\\{sr\\}";
    private static String rexSeparatorNote     = "\\{nt\\}";

    //Bibles cache
    private static List<Bible> versions = null;
    private static HashMap<String, VirtualFolder> bibleVirtualFileCache = new HashMap<String, VirtualFolder>();

    //Bookmarks cache
    private static VirtualFolder bookmarksFile;
    private static HashMap<BookMarkGroup,List<BookMark>> cacheGrupos;

    public static char separatorName = '\\';

    long cacheChapterSize = 0;


    public static void cleanBiblesCache() throws IOException{
        if(versions!=null){
            versions.clear();
            versions = null;
        }
        if(bibleVirtualFileCache!=null){

            Iterator<VirtualFolder> it = bibleVirtualFileCache.values().iterator();
            while(it.hasNext()){
                VirtualFolder vf = it.next();
                vf.close();
            }
            bibleVirtualFileCache.clear();
        }
    }

    public static void cleanBookmarksCache(){
        if(cacheGrupos!=null){
            cacheGrupos.clear();
        }
    }




    public static String root="bibles";


    private static byte[] read(String version,String name) throws IOException{
        VirtualFolder vf = null;
        if(bibleVirtualFileCache.containsKey(version)){
            vf = bibleVirtualFileCache.get(version);
        }else{
            vf = new VirtualFolder(root+ File.separator+version,true);
            bibleVirtualFileCache.put(version, vf);
        }

        return vf.read(name);
    }

    public static List<Bible> getVersions() throws IOException{

        if(versions!=null){
            return versions;
        }

        versions = new ArrayList<Bible>();
        File file = new File(root);

        File[] files = file.listFiles();

        if(files !=null){
            for(File f : files){
                if(!f.getName().endsWith(".files")){
                    try {
                        Bible bible = getBible(f.getName());
                        if(bible!=null){
                            versions.add(bible);
                        }
                    } catch (Exception e) {
                        Utils.printToLog("Error al obtener la biblia: "+f.getName()+"["+e.getMessage()+"]", e, Preferences.LOG_LEVEL_ERROR);
                    }
                }
            }
        }
        
        return versions;

    }

    public static Bible getBible(String version) throws Exception{

        Utils.printToLog("Leyendo biblia version = "+version, null, Preferences.LOG_LEVEL_DEBUG);

        Bible bible = new Bible();
        bible.setAbreviation("."+version);
        bible.setBooks(new ArrayList<Book>());
        
        byte[] datos = null;
        datos = read(version,version);
        setBooksFromFileInfo(bible, version, datos);
        try{
            datos = read(version,version+".info");
            setBibleInfoFromBibleFile(bible, version, datos);
        }catch(Exception e){
            Utils.printToLog("Error al obtener la biblia", e, Preferences.LOG_LEVEL_ERROR);
        }
        return bible;
    }

    public static void setBibleInfoFromBibleFile(Bible bible, String version, byte[] datos) throws Exception{

        String text = new String(datos);
        String tag;
        int startTag,endTag;

        tag = "language";
        startTag = text.indexOf(tag+"::")+tag.length()+2;
        endTag   = text.indexOf("::"+tag);
        String dato = text.substring(startTag, endTag);
        bible.setLanguage(dato);


        tag = "copyRight";
        startTag = text.indexOf(tag+"::")+tag.length()+2;
        endTag   = text.indexOf("::"+tag);
        bible.setCopyRight(text.substring(startTag, endTag));
        if(bible.getCopyRight().equals("null")){
            bible.setCopyRight(null);
        }

        tag = "copyRightContactName";
        startTag = text.indexOf(tag+"::")+tag.length()+2;
        endTag   = text.indexOf("::"+tag);
        bible.setCopyRightContactName(text.substring(startTag, endTag));
        if(bible.getCopyRightContactName().equals("null")){
            bible.setCopyRightContactName(null);
        }

        tag = "copyRightContactNote";
        startTag = text.indexOf(tag+"::")+tag.length()+2;
        endTag   = text.indexOf("::"+tag);
        bible.setCopyRightContactNote(text.substring(startTag, endTag));
        if(bible.getCopyRightContactNote().equals("null")){
            bible.setCopyRightContactNote(null);
        }

        tag = "copyRightContactAdrs";
        startTag = text.indexOf(tag+"::")+tag.length()+2;
        endTag   = text.indexOf("::"+tag);
        bible.setCopyRightContactAdrs(text.substring(startTag, endTag));
        if(bible.getCopyRightContactAdrs().equals("null")){
            bible.setCopyRightContactAdrs(null);
        }

        tag = "about";
        startTag = text.indexOf(tag+"::")+tag.length()+2;
        endTag   = text.indexOf("::"+tag);
        bible.setAbout(text.substring(startTag, endTag));
        if(bible.getAbout().equals("null")){
            bible.setAbout(null);
        }

    }


    public static String serializeBibleInfo(Bible bible) throws IOException{
        StringBuilder sb = new StringBuilder();
        sb.append("language::");
        sb.append(bible.getLanguage());
        sb.append("::language");

        sb.append("copyRight::");
        sb.append(bible.getCopyRight());
        sb.append("::copyRight");

        sb.append("copyRightContactName::");
        sb.append(bible.getCopyRightContactName());
        sb.append("::copyRightContactName");

        sb.append("copyRightContactNote::");
        sb.append(bible.getCopyRightContactNote());
        sb.append("::copyRightContactNote");

        sb.append("copyRightContactAdrs::");
        sb.append(bible.getCopyRightContactAdrs());
        sb.append("::copyRightContactAdrs");

        sb.append("about::");
        sb.append(bible.getAbout());
        sb.append("::about");

        return sb.toString();
    }



    public static void setBooksFromFileInfo(Bible bible,String version,byte[] datos) throws Exception{


        if(bible.getBooks() == null){
            bible.setBooks(new ArrayList<com.simplebible.bible.objects.Book>());
        }

        int lineCounter = 1;
        int lineStart = 0;
        int bookOrder = 1;

        for(int i=0;i<datos.length;i++){
            byte b = datos[i];
            if(b == '\n'){

                if(lineCounter == 1){
                    bible.setHumanName((new String(datos,lineStart,i-lineStart,"UTF-8")).trim());
                    Utils.printToLog("Nombre humano encontrado = "+bible.getHumanName(), null, Preferences.LOG_LEVEL_DEBUG);
                }else if(lineCounter == 2){

                }else if(lineCounter > 2){
                    String str =new String(datos,lineStart,i-lineStart,"UTF-8");
                    if(str.trim().equals("")){
                        Utils.printToLog("Ignorando linea "+lineCounter+" ya que esta vacia", null, Preferences.LOG_LEVEL_WARNING);
                        continue;
                    }
                    String[] databook = (str).split(",");
                    Book book = new BookLazy(databook[0].trim()+"."+version,databook[1].trim(),Integer.parseInt(databook[2].trim()),false);
                    book.setChapters(new ArrayList<Chapter>());
                    book.setId(bookOrder);
                    book.setOrden(bookOrder);
                    //Agregando capitulos
                    for(int icap=0;icap< book.getChaptersCount();icap++){
                        ChapterLazy chl = new ChapterLazy();
                        chl.setAbreviation(book.getAbreviation().cloneChanging(Abreviation.FIELD_CHAPTER,(icap+1)+""));
                        chl.setOrden(icap);
                        chl.setId(icap);
                        chl.setHumanName((icap+1)+"");
                        book.getChapters().add(chl);
                        Utils.printToLog("Agrego ChapterLazy = "+chl.getAbreviation().toString()+" [No se carga el capitulo ya que es de tipo Lazy]", null, Preferences.LOG_LEVEL_DEBUG);
                    }

                    bible.getBooks().add(book);
                    bookOrder++;
                }

                lineCounter++;
                lineStart = i+1;
            }
        }

    }


    

    public static void readChapter(Chapter ch) throws Exception{

        Abreviation abrv = ch.getAbreviation();

        if(abrv == null || abrv.getBible()==null || abrv.getBook() == null || abrv.getChapter() == null){
            Utils.printToLog("No se puede leer el capitulo ya que falta un dato en el abreviation = "+ch.getAbreviation().toString(), null, Preferences.LOG_LEVEL_ERROR);
            throw new Exception("No se puede leer el capitulo: "+abrv);
        }


        Utils.printToLog("Cargando capitulo = "+ch.getAbreviation().toString(), null, Preferences.LOG_LEVEL_DEBUG);

        byte[] buff = read(abrv.getBible(), abrv.getBook()+separatorName+(abrv.getChapter()+".sb"));

        Utils.printToLog("Archivo de capítulo cargado = "+new String(buff,"UTF-8"), null, Preferences.LOG_LEVEL_DEBUG);

        List<Verse> verses = new ArrayList<Verse>();
        List<Title> titles = new ArrayList<Title>();
        String[] topics = (new String(buff,"UTF-8")).split(rexSeparatorTopic);
        String[] strVerses = topics[3].split(rexSeparatorLine);
        String[] strTitles = topics[4].split(rexSeparatorLine);
        int verseCounter = 1;

        ch.setHumanName(topics[2]);
        

        //Getting verses
        for(String strv : strVerses){

            strv = strv.trim();
            if(strv.equals("")){
                continue;
            }

            Verse v = parseVerse(strv);
            if (v != null) {
                v.setOrden(verseCounter);
                v.setId(verseCounter);
                verses.add(v);
                verseCounter++;
            }
        }
        //Getting titles
        for(String strt : strTitles){

            strt = strt.trim();
            if(strt.equals("")){
                continue;
            }

            Title t = parseTitle(strt);
            if(t != null){
                titles.add(t);
            }
        }

        ch.setVerses(verses);
        ch.setTitles(titles);
    }

    private static Verse parseVerse(String str) throws Exception{

        Utils.printToLog("Interpretando verso = "+str, null, Preferences.LOG_LEVEL_DEBUG);

        Verse verse = new Verse();
        String columns[] = str.split(rexSeparatorColumn);
        verse.setAbreviation(columns[0].trim());
        verse.setHumanName(columns[1].trim());
        verse.setOrden(Integer.parseInt(columns[2].trim()));

        if(columns.length > 3){
            verse.setText(columns[3].trim());
        }else{
            verse.setText("");
        }

        if(columns.length > 4){
            for(int i=4;i<columns.length;i++){
                if(columns[i]!= null && !columns[i].trim().equals("")){
                    int start = columns[i].indexOf(startReference);
                    int end   = columns[i].indexOf(endReference);

                    if(start < 0 || end < 0){
                        continue;
                    }else{
                        String textRef = columns[i].substring(start+startReference.length(),end);
                        if(!textRef.trim().startsWith("note:")){
                            Referencia refs = leerReferenciasCruzadas(textRef);
                            if(verse.getRefCruzadas()==null){
                                verse.setRefCruzadas(new ArrayList<Referencia>());
                            }
                            verse.getRefCruzadas().add(refs);
                        }else{
                            Note note = parseNote(textRef);
                            if(verse.getNotes()==null){
                                verse.setNotes(new ArrayList<Note>());
                            }
                            note.setAbreviation(verse.getAbreviation());
                            verse.getNotes().add(note);
                        }
                    }
                }
            }
        }
        return verse;
    }


    public static Note parseNote(String str) {
        str = str.trim();
        if (str.startsWith("note:")) {
            str = str.substring(5, str.length());
        }

        String noteData[] = str.split(rexSeparatorNote);
        Note note = new Note();
        note.setHumanName(noteData[0].trim().equals("null") ? null:noteData[0].trim());
        note.setOrden(Integer.parseInt(noteData[1]));
        note.setId(Integer.parseInt(noteData[2]));
        note.setRelatedText(noteData[3].trim().equals("null") ? null:noteData[3].trim());
        note.setText(noteData[4].trim().equals("null") ? null:noteData[4].trim());

        note.setPosicion("##"+note.getOrden());

        return note;

    }


    public static Title parseTitle(String str){
        Utils.printToLog("Interpretando título = "+str, null, Preferences.LOG_LEVEL_DEBUG);
        String[] data = str.split(rexSeparatorColumn);
        Title t = new Title();
        t.setPosition(data[0]);
        t.setHumanName(data[1]);
        return t;
    }



    public static String serializeChapter(Chapter ch){
        /**
         * Example:
         * Topic 1: gen.1#st#
         * Topic 2: 1#st#
         * Topic 3: Génesis 1#st#
         * Topic 4: gen.1.1#sc#1#sc#1#sc#En el principio creó Dios #1 los cielos y la tierra.#sc#[#1 Gen.1.1]
         * ......
         * #st#
         * Topic 5:0#sc#La creación
         */
        StringBuilder sb = new StringBuilder();
        sb.append(ch.getAbreviation().toString());
        sb.append(separatorTopic);
        sb.append(Integer.toString(ch.getOrden()));
        sb.append(separatorTopic);
        sb.append(ch.getHumanName());
        sb.append(separatorTopic);
        sb.append("\n");
        for (int i = 0; i < ch.getVerses().size(); i++) {
            Verse v = ch.getVerses().get(i);
            sb.append(v.getAbreviation().toString() + separatorColumn + v.getHumanName() + separatorColumn + Integer.toString(v.getOrden()) + separatorColumn + v.getText());
            //Referencias cruzadas
            if (v.getRefCruzadas() != null && !v.getRefCruzadas().isEmpty()) {
                for (Referencia r : v.getRefCruzadas()) {

                    sb.append(separatorColumn);

                    sb.append(startReference);
                    sb.append(r.getPosicion());
                    if (r.getReferencias() != null) {
                        for (Abreviation vref : r.getReferencias()) {
                            if (vref == null) {
                                Utils.printToLog("######## Error referencia es NULL ###########",null,Preferences.LOG_LEVEL_ERROR);
                            } else {
                                String svref = vref.toString();
                                if (svref == null) {
                                    Utils.printToLog("######## Error referencia es NULL ###########",null,Preferences.LOG_LEVEL_ERROR);
                                } else {
                                    sb.append(separatorReference);
                                    sb.append(svref);
                                }
                            }
                        }
                    }
                    sb.append(endReference);
                }
            }
            //Notas
            if(v.getNotes()!=null && !v.getNotes().isEmpty()){
                for(Note n : v.getNotes()){
                    sb.append(separatorColumn);
                    sb.append(startReference);
                    sb.append("note:");
                    sb.append(n.getHumanName());
                    sb.append(separatorNote);
                    sb.append(n.getOrden());
                    sb.append(separatorNote);
                    sb.append(n.getId());
                    sb.append(separatorNote);
                    sb.append(n.getRelatedText());
                    sb.append(separatorNote);
                    sb.append(n.getText());
                    sb.append(endReference);
                }
            }

            sb.append(separatorLine);
            sb.append("\n");
        }
        sb.append(separatorTopic);
        sb.append("\n");

        if(ch.getTitles()!=null)
        for (Title t : ch.getTitles()) {
            sb.append(t.getPosition() + separatorColumn + t.getHumanName());
            sb.append(separatorLine);
            sb.append("\n");
        }
        return sb.toString();
    }


    public static void writeChapter(Chapter ch, File file) throws Exception {

        /**
         * Example:
         * Topic 1: gen.1#st#
         * Topic 2: 1#st#
         * Topic 3: Génesis 1#st#
         * Topic 4: gen.1.1#sc#1#sc#1#sc#En el principio creó Dios #1 los cielos y la tierra.#sc#[#1 Gen.1.1]
         * ......
         * #st#
         * Topic 5:0#sc#La creación
         */

        FileWriter fw = new FileWriter(file);
        try {
            String serialized = serializeChapter(ch);
            fw.write(serialized);
        } catch (Exception e) {
            Utils.printToLog("Error al escribir el capitulo: "+file.getName()+"["+e.getMessage()+"]", e, Preferences.LOG_LEVEL_ERROR);
        } finally {
            try {
                fw.close();
            } catch (Exception e) {
                Utils.printToLog("Error al cerrar el archivo", e, Preferences.LOG_LEVEL_ERROR);
            }
        }

    }


    private static Referencia leerReferenciasCruzadas(String str){

        String[] data = str.split(rexSeparatorReference);

        Referencia ref = new Referencia();
        ref.setPosicion(data[0].trim());
        ref.setReferencias(new ArrayList<Abreviation>());

        for(int i=1;i<data.length;i++){
            ref.getReferencias().add(Abreviation.parse(data[i].trim().toLowerCase()));
        }

        return ref;
        
    }

    private static Referencia parseReferencia(String txt){


        Utils.printToLog("Interpretando referencia = " + txt, null, Preferences.LOG_LEVEL_DEBUG);

        Referencia ref = new Referencia();
        List<Abreviation> list = new ArrayList<Abreviation>();
        String[] data = txt.split(";");

        if(data.length < 2){
            return null;
        }

        ref.setPosicion(data[0]);

        for(int i=1;i<data.length;i++){
            try{
                list.add(Abreviation.parse(data[i].trim()));
            }catch(Exception e){
                Utils.printToLog("No fue posible obtener la referencia: "+data[i], e, Preferences.LOG_LEVEL_ERROR);
            }
        }
        if(list.isEmpty()){
            return null;
        }
        ref.setReferencias(list);
        return ref;
    }



    ///BOOKMARKS

    public static List<BookMark> getBookMarks(Chapter ch) throws IOException{
        String fileName = getBookmarkFile(ch.getAbreviation());
        List<BookMark> book = readBookmarksFile(fileName);
        return book;
    }



    public static BookMarkGroup getBookMarkGroup(String name) throws IOException{
        BookMarkGroup bmg = new BookMarkGroup();
        bmg.setGroupName(name);

        if(getBookmarkCache()!=null){
            for(BookMarkGroup b : getBookmarkCache().keySet()){
                if(bmg.equals(b)){
                    return b;
                }
            }
        }
        return null;
    }

    public static BookMark getBookMark(int id, Abreviation abrv) throws IOException{
        List<BookMark> list = readBookmarksFile(getBookmarkFile(abrv));
        if(list == null) return null;
        
        for(BookMark b : list){
            if(b.getId() == id){
                return b;
            }
        }
        return null;
    }


    public static void deleteBookmarksGroup(BookMarkGroup bg) throws IOException{
        List<BookMark> list = getBookmarks(bg);
        for(BookMark bm: list){
            deleteBookmark(bm,false);
            if(bm.getGrupos().size()>1){
                bm.getGrupos().remove(bg);
                saveBookmark(bm);
            }
        }
        if(cacheGrupos!=null){
            cacheGrupos.clear();
            cacheGrupos = null;
        }
    }


    /**
     * Elimina un marcador de un grupo o eliminado por completo si el marcador solo
     * pertenece a ese grupo
     * @param bm
     * @param bmg
     * @throws IOException
     */
    public static void deleteBookmarkFromGroup(BookMark bm, BookMarkGroup bmg) throws IOException{
        if(!bm.getGrupos().contains(bmg)){
            throw new IOException("BookMark["+bm.getPalabrasClave()+"] is not part of Group["+bmg.getGroupName()+"]");
        }
        deleteBookmark(bm,false);
        bm.getGrupos().remove(bmg);
        if(bm.getGrupos().size()>0){
            saveBookmark(bm, false, false);
        }
        if(cacheGrupos!=null){
            cacheGrupos.clear();
            cacheGrupos = null;
        }
    }

    /**
     * Elimina el marcador de todos los grupos a los que pertenece
     * @param b
     * @throws IOException
     */
    public static void deleteBookmark(BookMark b) throws IOException{
        deleteBookmark(b,true);
    }

    private static void deleteBookmark(BookMark b, boolean cleanCache) throws IOException{
        String file = getBookmarkFile(b);
        List<BookMark> list = readBookmarksFile(file);

        getBookmarksVD().truncate(file);

        for(BookMark bm:list){
            if(!bm.equals(b)){
                saveBookmark(bm,false,false);
            }
        }
        if(cleanCache && cacheGrupos!=null){
            cacheGrupos.clear();
            cacheGrupos = null;
        }
    }


    public static List<BookMarkGroup> getBookmarkGroup() throws  IOException{

        List<BookMarkGroup> gl = new ArrayList<BookMarkGroup>();
        for(BookMarkGroup bg: getBookmarkCache().keySet()){
            gl.add(bg);
        }

        return gl;
    }

    public static List<BookMark> getBookmarks(BookMarkGroup group) throws IOException {

        if(getBookmarkCache().get(group)!=null){
            List<BookMark> bm = getBookmarkCache().get(group);
            return bm;
        }

        Utils.printToLog("Obteniendo los marcadores del grupo: "+group.getGroupName(), null, Preferences.LOG_LEVEL_INFO);

        String[] files = getBookmarksVD().getFiles();
        if (files == null) {
            return null;
        }



        List<BookMark> list = new ArrayList<BookMark>();

        for (String s : files) {
            List<BookMark> l = readBookmarksFile(s);
            if (l != null) {
                for (BookMark b : l) {
                    try {
                        if (b.getGrupos().contains(group)) {
                            list.add(b);
                        }
                    } catch (Exception e) {
                        Utils.printToLog("Error no se puede agergar el grupo", e, Preferences.LOG_LEVEL_ERROR);
                    }
                }
            }
        }

        if(!list.isEmpty()){
            getBookmarkCache().put(group, list);
        }

        return getBookmarkCache().get(group);
    }

    private static List<BookMark> readBookmarksFile(String abrv) throws IOException{
       if(!getBookmarksVD().exists(abrv)){
           return null;
       }
       byte[] data = getBookmarksVD().read(abrv);
        if(data==null || data.length == 0){
            return null;
        }
        List<BookMark> lista = new ArrayList<BookMark>();
        int start=0;
        int count = 0;
        for(int i=0;i<data.length;i++){
            if(data[i]=='\n'){
                String linea = new String(data,start, i-start, "UTF-8");
                BookMark b=desSerializarBookmark(linea);
                if(b!=null){
                    count++;
                    lista.add(b);
                }
                start = i+1;
            }
        }
        return lista;
    }


    public  static void saveBookmark(BookMark bm) throws IOException{
        saveBookmark(bm, true,true);
    }

    private static void saveBookmark(BookMark bm,boolean updateCache,boolean generateId) throws IOException{
       String file = getBookmarkFile(bm);

        if (generateId) {
            int id = 1;
            if (getBookmarksVD().exists("bookmarkid")) {
                id = Integer.parseInt(new String(getBookmarksVD().read("bookmarkid")));
                id++;
            }
            getBookmarksVD().write("bookmarkid", Integer.toString(id).getBytes());
            bm.setId(id);
        }
       
       getBookmarksVD().append(file,(serializarBookmark(bm)+"\n").getBytes());

       //actualizando cache
       if(updateCache && cacheGrupos!=null){
           cacheGrupos.clear();
           cacheGrupos = null;
        }
    }

    public static String getBookmarkFile(BookMark bm){
        return  getBookmarkFile(bm.getAbreviation());
    }

    public static String getBookmarkFile(Abreviation ab){
        return  ab.getBook()+"." + ab.getChapter();
    }

    public static String serializarBookmark(BookMark bm){
        String c1 = bm.getAbreviation().toString();
        String c2 = "";

        for(BookMarkGroup bmg : bm.getGrupos()){
            c2 += ","+bmg.getGroupName();
        }

        String c3 = "null";
        if(bm.getColor()!=null){
            c3 = bm.getColor().getRGB()+"";
        }
        String c4 = Calendar.getInstance().getTimeInMillis()+"";
        String c5 = bm.getPalabrasClave();
        String c6 = bm.getComentario().replaceAll("\\r\\n", "\\n");
        c6 = bm.getComentario().replaceAll("\\n", "\\n");
        String c7 = Integer.toString(bm.getId());

        return c1 + "{s}" + c2+ "{s}" + c3+ "{s}" + c4+ "{s}" + c5+ "{s}" + c6 + "{s}"+c7+"\n";
    }

    public static BookMark desSerializarBookmark(String str){

        if(str.trim().equals("")){
            return null;
        }

        String[] data = str.split("\\{s\\}");
        BookMark bm = new BookMark();
        bm.setAbreviation(data[0].trim());

        bm.setGrupos(new ArrayList<BookMarkGroup>());
        String[] arrGroups = data[1].trim().split(",");
        for(String s : arrGroups){
            if(s.trim().equals("")) continue;
            BookMarkGroup bmg = new BookMarkGroup();
            bmg.setGroupName(s.trim());
            bm.getGrupos().add(bmg);
        }
        
        if(!data[2].trim().equals("null")){
            bm.setColor(new Color(Integer.parseInt(data[2].trim())));
        }
        Calendar c = Calendar.getInstance();
        c.setTimeInMillis(Long.parseLong(data[3].trim()));
        bm.setFecha(c);
        bm.setPalabrasClave(data[4].trim());
        bm.setComentario(data[5].trim());
        bm.setId(Integer.parseInt(data[6].trim()));
        return bm;
    }


    public static VirtualFolder getBookmarksVD() throws IOException{
        if(bookmarksFile ==null){
            bookmarksFile = new VirtualFolder("bookmarks",false);
        }
        return bookmarksFile;
    }


    public static HashMap<BookMarkGroup,List<BookMark>> getBookmarkCache() throws IOException{
        if(cacheGrupos == null){
            cacheGrupos = new HashMap<BookMarkGroup, List<BookMark>>();


            String[] files = getBookmarksVD().getFiles();
            if (files == null) {
                return null;
            }

            List<BookMarkGroup> groupObject = new ArrayList<BookMarkGroup>();
            for (String s : files) {
                List<BookMark> l = readBookmarksFile(s);
                if (l != null) {
                    for (BookMark b : l) {
                        try {
                            for (BookMarkGroup bg : b.getGrupos()) {
                                //if (cacheGrupos.get(bg) == null) {
                                //    cacheGrupos.put(bg, new ArrayList<BookMark>());
                                //}
                                //cacheGrupos.get(bg).add(b);
                                //bg.setCountMarcadores(cacheGrupos.get(bg).size());
                                if(!cacheGrupos.containsKey(bg)){
                                    cacheGrupos.put(bg,null);
                                    groupObject.add(bg);
                                }
                                BookMarkGroup objKey = groupObject.get(groupObject.indexOf(bg));
                                objKey.setCountMarcadores(objKey.getCountMarcadores()+1);
                            }
                        } catch (Exception e) {
                            Utils.printToLog("Error no se puede agergar el grupo", e, Preferences.LOG_LEVEL_ERROR);
                        }
                    }
                }
            }

        }
        return cacheGrupos;
    }
 

}






